package com.goalias.filter;

import com.goalias.util.JWTUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.SignatureException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

@Component
public class JwtAuthFilter implements GlobalFilter, Ordered {

    @Resource
    private RedisTemplate redisTemplate;

    @Value("${auth.secret}")
    private String jwtSecret;
    @Value("${auth.tokenName}")
    private String jwtTokenName;
    @Value("${auth.loginPath}")
    private List<String> loginPath;//需要登陆的才拦截

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String bearerToken = exchange.getRequest().getHeaders().getFirst(jwtTokenName);
        String routePath = exchange.getRequest().getURI().getPath();

        boolean nonLogin = true;
        Iterator<String> iterator = loginPath.iterator();
        while (iterator.hasNext()) {
            String path = iterator.next();
            if (routePath.startsWith(path)) {
                nonLogin = false;
                break;
            }
        }
        if (StringUtils.hasText(bearerToken) && nonLogin) {
            try {
                String userId = (String) JWTUtil.parseJWT(jwtSecret, bearerToken.substring(7)).get("userId");
                exchange.getRequest().mutate()
                        .header("userId", userId)
                        .build();
            }catch (SignatureException e){
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }catch (ExpiredJwtException e){
                e.printStackTrace();
                //不做处理
            }
        }
        //需要登陆
        if (nonLogin) {
            return chain.filter(exchange);
        }

        if (!StringUtils.hasText(bearerToken) || !bearerToken.startsWith("Bearer ")) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        try {
            String token = bearerToken.substring(7);
            Claims claims = JWTUtil.parseJWT(jwtSecret, token);
            String userId = claims.getSubject();
            Object unUseToken = redisTemplate.opsForValue().get("user:token:" + userId);
            if (Objects.nonNull(unUseToken) && unUseToken.toString().equals(bearerToken)) {
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }//退出登录失效的token

            // 将解析的用户信息传递给下游微服务
            exchange.getRequest().mutate()
                    .header("userId", userId)
                    .build();
        } catch (Exception e) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -3;
    }
}

